import javax.swing.*;
import java.awt.*;
import java.util.List;
import java.util.concurrent.*;

class GraphPanel extends JPanel {
    private final ConcurrentLinkedDeque<Point> sinPoints = new ConcurrentLinkedDeque<>();
    private final ConcurrentLinkedDeque<Point> cosPoints = new ConcurrentLinkedDeque<>();
    private final ConcurrentLinkedDeque<Point> halfPoints = new ConcurrentLinkedDeque<>();
    private final ConcurrentLinkedDeque<Point> twicePoints = new ConcurrentLinkedDeque<>();

    private final int PANEL_WIDTH = 600;
    private final int PANEL_HEIGHT = 400;
    private final int DOT_SIZE = 3;
    private final double SPEED = -1; // 点的水平移动速度

    public GraphPanel() {}


    public void updateSinGraph(double value) {
        ConcurrentLinkedDeque<Point> points = sinPoints;
        double x = PANEL_WIDTH - 100;
        double y = PANEL_HEIGHT / 2 - 50 * Math.sin(value * 0.3);
        points.addLast(new Point(x, y));

        for (Point p : points) {
            p.setX(p.getX() + SPEED);
        }

        if (!points.isEmpty()) {
            Point point = points.getFirst();
            if (point.getX() < 0) {
                points.pollFirst();
            }
        }
    }

    public void updateCosGraph(double value) {
        ConcurrentLinkedDeque<Point> points = cosPoints;
        double x = PANEL_WIDTH - 100;
        double y = PANEL_HEIGHT / 2 - 50 * Math.cos(value * 0.3);
        points.addLast(new Point(x, y));

        for (Point p : points) {
            p.setX(p.getX() + SPEED);
        }

        // 移除超出左边界的点
        if (!points.isEmpty()) {
            Point point = points.getFirst();
            if (point.getX() < 0) {
                points.pollFirst();
            }
        }
    }

    public void updateHalfGraph(double value) {
        ConcurrentLinkedDeque<Point> points = halfPoints;
        double x = PANEL_WIDTH - 100;
        double y = PANEL_HEIGHT / 2 - 0.5 * value * 5;
        points.addLast(new Point(x, y));

        for (Point p : points) {
            p.setX(p.getX() + SPEED);
        }

        // 移除超出左边界的点
        if (!points.isEmpty()) {
            Point point = points.getFirst();
            if (point.getX() < 0) {
                points.pollFirst();
            }
        }
    }


    public void updateTwiceGraph(double value) {
        ConcurrentLinkedDeque<Point> points = twicePoints;
        double x = PANEL_WIDTH - 100;
        double y = PANEL_HEIGHT / 2 - 2 * value * 5;
        points.addLast(new Point(x, y));
        for (Point p : points) {
            p.setX(p.getX() + SPEED);
        }
        // 移除超出左边界的点
        if (!points.isEmpty()) {
            Point point = points.getFirst();
            if (point.getX() < 0) {
                points.pollFirst();
            }
        }
    }



    public void repaintGraph() {
        SwingUtilities.invokeLater(() -> repaint());
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        int width = getWidth();
        int height = getHeight();

        int originX = 50;
        int originY = height / 2;

        g.setColor(Color.BLACK);
        g.drawLine(originX, originY, width - 50, originY);
        g.drawLine(width - 50, originY, width - 60, originY - 10);
        g.drawLine(width - 50, originY, width - 60, originY + 10);

        g.drawLine(originX, 50, originX, height - 50);
        g.drawLine(originX, 50, originX - 10, 60);
        g.drawLine(originX, 50, originX + 10, 60);

        g.setColor(Color.RED);
        if (!sinPoints.isEmpty()) {
            for (Point p : sinPoints) {
                g.fillOval((int)p.getX(), (int)p.getY(), DOT_SIZE, DOT_SIZE);
            }
            Value.set(0, (PANEL_HEIGHT / 2 - sinPoints.getLast().getY()) / 50);
        }

        g.setColor(Color.BLUE);
        if (!cosPoints.isEmpty()) {
            for (Point p : cosPoints) {
                g.fillOval((int)p.getX(), (int)p.getY(), DOT_SIZE, DOT_SIZE);
            }
            Value.set(1, (PANEL_HEIGHT / 2 - cosPoints.getLast().getY()) / 50);
        }


        g.setColor(Color.GREEN);
        if (!halfPoints.isEmpty()) {
            for (Point p : halfPoints) {
                g.fillOval((int)p.getX(), (int)p.getY(), DOT_SIZE, DOT_SIZE);
            }
            Value.set(2, ((PANEL_HEIGHT / 2 - halfPoints.getLast().getY()) / 50));
        }


        g.setColor(Color.YELLOW);
        if (!twicePoints.isEmpty()) {
            for (Point p : twicePoints) {
                g.fillOval((int)p.getX(), (int)p.getY(), DOT_SIZE, DOT_SIZE);
            }
            Value.set(3, ((PANEL_HEIGHT / 2  - twicePoints.getLast().getY()) / 50));
        }

    }
}